home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / g_monster.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  17.9 KB  |  741 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "g_local.h"
  21.  
  22.  
  23. //
  24. // monster weapons
  25. //
  26.  
  27. //FIXME mosnters should call these with a totally accurate direction
  28. // and we can mess it up based on skill.  Spread should be for normal
  29. // and we can tighten or loosen based on skill.  We could muck with
  30. // the damages too, but I'm not sure that's such a good idea.
  31. void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype)
  32. {
  33.     fire_bullet (self, start, dir, damage, kick, hspread, vspread, MOD_UNKNOWN);
  34.  
  35.     gi.WriteByte (svc_muzzleflash2);
  36.     gi.WriteShort (self - g_edicts);
  37.     gi.WriteByte (flashtype);
  38.     gi.multicast (start, MULTICAST_PVS);
  39. }
  40.  
  41. void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype)
  42. {
  43.     fire_shotgun (self, start, aimdir, damage, kick, hspread, vspread, count, MOD_UNKNOWN);
  44.  
  45.     gi.WriteByte (svc_muzzleflash2);
  46.     gi.WriteShort (self - g_edicts);
  47.     gi.WriteByte (flashtype);
  48.     gi.multicast (start, MULTICAST_PVS);
  49. }
  50.  
  51. void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect)
  52. {
  53.     fire_blaster (self, start, dir, damage, speed, effect, false);
  54.  
  55.     gi.WriteByte (svc_muzzleflash2);
  56.     gi.WriteShort (self - g_edicts);
  57.     gi.WriteByte (flashtype);
  58.     gi.multicast (start, MULTICAST_PVS);
  59. }    
  60.  
  61. void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype)
  62. {
  63.     fire_grenade (self, start, aimdir, damage, speed, 2.5, damage+40);
  64.  
  65.     gi.WriteByte (svc_muzzleflash2);
  66.     gi.WriteShort (self - g_edicts);
  67.     gi.WriteByte (flashtype);
  68.     gi.multicast (start, MULTICAST_PVS);
  69. }
  70.  
  71. void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype)
  72. {
  73.     fire_rocket (self, start, dir, damage, speed, damage+20, damage);
  74.  
  75.     gi.WriteByte (svc_muzzleflash2);
  76.     gi.WriteShort (self - g_edicts);
  77.     gi.WriteByte (flashtype);
  78.     gi.multicast (start, MULTICAST_PVS);
  79. }    
  80.  
  81. void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype)
  82. {
  83.     fire_rail (self, start, aimdir, damage, kick);
  84.  
  85.     gi.WriteByte (svc_muzzleflash2);
  86.     gi.WriteShort (self - g_edicts);
  87.     gi.WriteByte (flashtype);
  88.     gi.multicast (start, MULTICAST_PVS);
  89. }
  90.  
  91. void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype)
  92. {
  93.     fire_bfg (self, start, aimdir, damage, speed, damage_radius);
  94.  
  95.     gi.WriteByte (svc_muzzleflash2);
  96.     gi.WriteShort (self - g_edicts);
  97.     gi.WriteByte (flashtype);
  98.     gi.multicast (start, MULTICAST_PVS);
  99. }
  100.  
  101.  
  102.  
  103. //
  104. // Monster utility functions
  105. //
  106.  
  107. static void M_FliesOff (edict_t *self)
  108. {
  109.     self->s.effects &= ~EF_FLIES;
  110.     self->s.sound = 0;
  111. }
  112.  
  113. static void M_FliesOn (edict_t *self)
  114. {
  115.     if (self->waterlevel)
  116.         return;
  117.     self->s.effects |= EF_FLIES;
  118.     self->s.sound = gi.soundindex ("infantry/inflies1.wav");
  119.     self->think = M_FliesOff;
  120.     self->nextthink = level.time + 60;
  121. }
  122.  
  123. void M_FlyCheck (edict_t *self)
  124. {
  125.     if (self->waterlevel)
  126.         return;
  127.  
  128.     if (random() > 0.5)
  129.         return;
  130.  
  131.     self->think = M_FliesOn;
  132.     self->nextthink = level.time + 5 + 10 * random();
  133. }
  134.  
  135. void AttackFinished (edict_t *self, float time)
  136. {
  137.     self->monsterinfo.attack_finished = level.time + time;
  138. }
  139.  
  140.  
  141. void M_CheckGround (edict_t *ent)
  142. {
  143.     vec3_t        point;
  144.     trace_t        trace;
  145.  
  146.     if (ent->flags & (FL_SWIM|FL_FLY))
  147.         return;
  148.  
  149.     if (ent->velocity[2] > 100)
  150.     {
  151.         ent->groundentity = NULL;
  152.         return;
  153.     }
  154.  
  155. // if the hull point one-quarter unit down is solid the entity is on ground
  156.     point[0] = ent->s.origin[0];
  157.     point[1] = ent->s.origin[1];
  158.     point[2] = ent->s.origin[2] - 0.25;
  159.  
  160.     trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID);
  161.  
  162.     // check steepness
  163.     if ( trace.plane.normal[2] < 0.7 && !trace.startsolid)
  164.     {
  165.         ent->groundentity = NULL;
  166.         return;
  167.     }
  168.  
  169. //    ent->groundentity = trace.ent;
  170. //    ent->groundentity_linkcount = trace.ent->linkcount;
  171. //    if (!trace.startsolid && !trace.allsolid)
  172. //        VectorCopy (trace.endpos, ent->s.origin);
  173.     if (!trace.startsolid && !trace.allsolid)
  174.     {
  175.         VectorCopy (trace.endpos, ent->s.origin);
  176.         ent->groundentity = trace.ent;
  177.         ent->groundentity_linkcount = trace.ent->linkcount;
  178.         ent->velocity[2] = 0;
  179.     }
  180. }
  181.  
  182.  
  183. void M_CatagorizePosition (edict_t *ent)
  184. {
  185.     vec3_t        point;
  186.     int            cont;
  187.  
  188. //
  189. // get waterlevel
  190. //
  191.     point[0] = ent->s.origin[0];
  192.     point[1] = ent->s.origin[1];
  193.     point[2] = ent->s.origin[2] + ent->mins[2] + 1;    
  194.     cont = gi.pointcontents (point);
  195.  
  196.     if (!(cont & MASK_WATER))
  197.     {
  198.         ent->waterlevel = 0;
  199.         ent->watertype = 0;
  200.         return;
  201.     }
  202.  
  203.     ent->watertype = cont;
  204.     ent->waterlevel = 1;
  205.     point[2] += 26;
  206.     cont = gi.pointcontents (point);
  207.     if (!(cont & MASK_WATER))
  208.         return;
  209.  
  210.     ent->waterlevel = 2;
  211.     point[2] += 22;
  212.     cont = gi.pointcontents (point);
  213.     if (cont & MASK_WATER)
  214.         ent->waterlevel = 3;
  215. }
  216.  
  217.  
  218. void M_WorldEffects (edict_t *ent)
  219. {
  220.     int        dmg;
  221.  
  222.     if (ent->health > 0)
  223.     {
  224.         if (!(ent->flags & FL_SWIM))
  225.         {
  226.             if (ent->waterlevel < 3)
  227.             {
  228.                 ent->air_finished = level.time + 12;
  229.             }
  230.             else if (ent->air_finished < level.time)
  231.             {    // drown!
  232.                 if (ent->pain_debounce_time < level.time)
  233.                 {
  234.                     dmg = 2 + 2 * floor(level.time - ent->air_finished);
  235.                     if (dmg > 15)
  236.                         dmg = 15;
  237.                     T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  238.                     ent->pain_debounce_time = level.time + 1;
  239.                 }
  240.             }
  241.         }
  242.         else
  243.         {
  244.             if (ent->waterlevel > 0)
  245.             {
  246.                 ent->air_finished = level.time + 9;
  247.             }
  248.             else if (ent->air_finished < level.time)
  249.             {    // suffocate!
  250.                 if (ent->pain_debounce_time < level.time)
  251.                 {
  252.                     dmg = 2 + 2 * floor(level.time - ent->air_finished);
  253.                     if (dmg > 15)
  254.                         dmg = 15;
  255.                     T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  256.                     ent->pain_debounce_time = level.time + 1;
  257.                 }
  258.             }
  259.         }
  260.     }
  261.     
  262.     if (ent->waterlevel == 0)
  263.     {
  264.         if (ent->flags & FL_INWATER)
  265.         {    
  266.             gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
  267.             ent->flags &= ~FL_INWATER;
  268.         }
  269.         return;
  270.     }
  271.  
  272.     if ((ent->watertype & CONTENTS_LAVA) && !(ent->flags & FL_IMMUNE_LAVA))
  273.     {
  274.         if (ent->damage_debounce_time < level.time)
  275.         {
  276.             ent->damage_debounce_time = level.time + 0.2;
  277.             T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 10*ent->waterlevel, 0, 0, MOD_LAVA);
  278.         }
  279.     }
  280.     if ((ent->watertype & CONTENTS_SLIME) && !(ent->flags & FL_IMMUNE_SLIME))
  281.     {
  282.         if (ent->damage_debounce_time < level.time)
  283.         {
  284.             ent->damage_debounce_time = level.time + 1;
  285.             T_Damage (ent, world, world, vec3_origin, ent->s.origin, vec3_origin, 4*ent->waterlevel, 0, 0, MOD_SLIME);
  286.         }
  287.     }
  288.     
  289.     if ( !(ent->flags & FL_INWATER) )
  290.     {    
  291.         if (!(ent->svflags & SVF_DEADMONSTER))
  292.         {
  293.             if (ent->watertype & CONTENTS_LAVA)
  294.                 if (random() <= 0.5)
  295.                     gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava1.wav"), 1, ATTN_NORM, 0);
  296.                 else
  297.                     gi.sound (ent, CHAN_BODY, gi.soundindex("player/lava2.wav"), 1, ATTN_NORM, 0);
  298.             else if (ent->watertype & CONTENTS_SLIME)
  299.                 gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  300.             else if (ent->watertype & CONTENTS_WATER)
  301.                 gi.sound (ent, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  302.         }
  303.  
  304.         ent->flags |= FL_INWATER;
  305.         ent->damage_debounce_time = 0;
  306.     }
  307. }
  308.  
  309.  
  310. void M_droptofloor (edict_t *ent)
  311. {
  312.     vec3_t        end;
  313.     trace_t        trace;
  314.  
  315.     ent->s.origin[2] += 1;
  316.     VectorCopy (ent->s.origin, end);
  317.     end[2] -= 256;
  318.     
  319.     trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  320.  
  321.     if (trace.fraction == 1 || trace.allsolid)
  322.         return;
  323.  
  324.     VectorCopy (trace.endpos, ent->s.origin);
  325.  
  326.     gi.linkentity (ent);
  327.     M_CheckGround (ent);
  328.     M_CatagorizePosition (ent);
  329. }
  330.  
  331.  
  332. void M_SetEffects (edict_t *ent)
  333. {
  334.     ent->s.effects &= ~(EF_COLOR_SHELL|EF_POWERSCREEN);
  335.     ent->s.renderfx &= ~(RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  336.  
  337.     if (ent->monsterinfo.aiflags & AI_RESURRECTING)
  338.     {
  339.         ent->s.effects |= EF_COLOR_SHELL;
  340.         ent->s.renderfx |= RF_SHELL_RED;
  341.     }
  342.  
  343.     if (ent->health <= 0)
  344.         return;
  345.  
  346.     if (ent->powerarmor_time > level.time)
  347.     {
  348.         if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SCREEN)
  349.         {
  350.             ent->s.effects |= EF_POWERSCREEN;
  351.         }
  352.         else if (ent->monsterinfo.power_armor_type == POWER_ARMOR_SHIELD)
  353.         {
  354.             ent->s.effects |= EF_COLOR_SHELL;
  355.             ent->s.renderfx |= RF_SHELL_GREEN;
  356.         }
  357.     }
  358. }
  359.  
  360.  
  361. void M_MoveFrame (edict_t *self)
  362. {
  363.     mmove_t    *move;
  364.     int        index;
  365.  
  366.     move = self->monsterinfo.currentmove;
  367.     self->nextthink = level.time + FRAMETIME;
  368.  
  369.     if ((self->monsterinfo.nextframe) && (self->monsterinfo.nextframe >= move->firstframe) && (self->monsterinfo.nextframe <= move->lastframe))
  370.     {
  371.         self->s.frame = self->monsterinfo.nextframe;
  372.         self->monsterinfo.nextframe = 0;
  373.     }
  374.     else
  375.     {
  376.         if (self->s.frame == move->lastframe)
  377.         {
  378.             if (move->endfunc)
  379.             {
  380.                 move->endfunc (self);
  381.  
  382.                 // regrab move, endfunc is very likely to change it
  383.                 move = self->monsterinfo.currentmove;
  384.  
  385.                 // check for death
  386.                 if (self->svflags & SVF_DEADMONSTER)
  387.                     return;
  388.             }
  389.         }
  390.  
  391.         if (self->s.frame < move->firstframe || self->s.frame > move->lastframe)
  392.         {
  393.             self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  394.             self->s.frame = move->firstframe;
  395.         }
  396.         else
  397.         {
  398.             if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
  399.             {
  400.                 self->s.frame++;
  401.                 if (self->s.frame > move->lastframe)
  402.                     self->s.frame = move->firstframe;
  403.             }
  404.         }
  405.     }
  406.  
  407.     index = self->s.frame - move->firstframe;
  408.     if (move->frame[index].aifunc)
  409.         if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
  410.             move->frame[index].aifunc (self, move->frame[index].dist * self->monsterinfo.scale);
  411.         else
  412.             move->frame[index].aifunc (self, 0);
  413.  
  414.     if (move->frame[index].thinkfunc)
  415.         move->frame[index].thinkfunc (self);
  416. }
  417.  
  418.  
  419. void monster_think (edict_t *self)
  420. {
  421.     M_MoveFrame (self);
  422.     if (self->linkcount != self->monsterinfo.linkcount)
  423.     {
  424.         self->monsterinfo.linkcount = self->linkcount;
  425.         M_CheckGround (self);
  426.     }
  427.     M_CatagorizePosition (self);
  428.     M_WorldEffects (self);
  429.     M_SetEffects (self);
  430. }
  431.  
  432.  
  433. /*
  434. ================
  435. monster_use
  436.  
  437. Using a monster makes it angry at the current activator
  438. ================
  439. */
  440. void monster_use (edict_t *self, edict_t *other, edict_t *activator)
  441. {
  442.     if (self->enemy)
  443.         return;
  444.     if (self->health <= 0)
  445.         return;
  446.     if (activator->flags & FL_NOTARGET)
  447.         return;
  448.     if (!(activator->client) && !(activator->monsterinfo.aiflags & AI_GOOD_GUY))
  449.         return;
  450.     
  451. // delay reaction so if the monster is teleported, its sound is still heard
  452.     self->enemy = activator;
  453.     FoundTarget (self);
  454. }
  455.  
  456.  
  457. void monster_start_go (edict_t *self);
  458.  
  459.  
  460. void monster_triggered_spawn (edict_t *self)
  461. {
  462.     self->s.origin[2] += 1;
  463.     KillBox (self);
  464.  
  465.     self->solid = SOLID_BBOX;
  466.     self->movetype = MOVETYPE_STEP;
  467.     self->svflags &= ~SVF_NOCLIENT;
  468.     self->air_finished = level.time + 12;
  469.     gi.linkentity (self);
  470.  
  471.     monster_start_go (self);
  472.  
  473.     if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET))
  474.     {
  475.         FoundTarget (self);
  476.     }
  477.     else
  478.     {
  479.         self->enemy = NULL;
  480.     }
  481. }
  482.  
  483. void monster_triggered_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
  484. {
  485.     // we have a one frame delay here so we don't telefrag the guy who activated us
  486.     self->think = monster_triggered_spawn;
  487.     self->nextthink = level.time + FRAMETIME;
  488.     if (activator->client)
  489.         self->enemy = activator;
  490.     self->use = monster_use;
  491. }
  492.  
  493. void monster_triggered_start (edict_t *self)
  494. {
  495.     self->solid = SOLID_NOT;
  496.     self->movetype = MOVETYPE_NONE;
  497.     self->svflags |= SVF_NOCLIENT;
  498.     self->nextthink = 0;
  499.     self->use = monster_triggered_spawn_use;
  500. }
  501.  
  502.  
  503. /*
  504. ================
  505. monster_death_use
  506.  
  507. When a monster dies, it fires all of its targets with the current
  508. enemy as activator.
  509. ================
  510. */
  511. void monster_death_use (edict_t *self)
  512. {
  513.     self->flags &= ~(FL_FLY|FL_SWIM);
  514.     self->monsterinfo.aiflags &= AI_GOOD_GUY;
  515.  
  516.     if (self->item)
  517.     {
  518.         Drop_Item (self, self->item);
  519.         self->item = NULL;
  520.     }
  521.  
  522.     if (self->deathtarget)
  523.         self->target = self->deathtarget;
  524.  
  525.     if (!self->target)
  526.         return;
  527.  
  528.     G_UseTargets (self, self->enemy);
  529. }
  530.  
  531.  
  532. //============================================================================
  533.  
  534. qboolean monster_start (edict_t *self)
  535. {
  536.     if (deathmatch->value)
  537.     {
  538.         G_FreeEdict (self);
  539.         return false;
  540.     }
  541.  
  542.     if ((self->spawnflags & 4) && !(self->monsterinfo.aiflags & AI_GOOD_GUY))
  543.     {
  544.         self->spawnflags &= ~4;
  545.         self->spawnflags |= 1;
  546. //        gi.dprintf("fixed spawnflags on %s at %s\n", self->classname, vtos(self->s.origin));
  547.     }
  548.  
  549.     if (!(self->monsterinfo.aiflags & AI_GOOD_GUY))
  550.         level.total_monsters++;
  551.  
  552.     self->nextthink = level.time + FRAMETIME;
  553.     self->svflags |= SVF_MONSTER;
  554.     self->s.renderfx |= RF_FRAMELERP;
  555.     self->takedamage = DAMAGE_AIM;
  556.     self->air_finished = level.time + 12;
  557.     self->use = monster_use;
  558.     self->max_health = self->health;
  559.     self->clipmask = MASK_MONSTERSOLID;
  560.  
  561.     self->s.skinnum = 0;
  562.     self->deadflag = DEAD_NO;
  563.     self->svflags &= ~SVF_DEADMONSTER;
  564.  
  565.     if (!self->monsterinfo.checkattack)
  566.         self->monsterinfo.checkattack = M_CheckAttack;
  567.     VectorCopy (self->s.origin, self->s.old_origin);
  568.  
  569.     if (st.item)
  570.     {
  571.         self->item = FindItemByClassname (st.item);
  572.         if (!self->item)
  573.             gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
  574.     }
  575.  
  576.     // randomize what frame they start on
  577.     if (self->monsterinfo.currentmove)
  578.         self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1));
  579.  
  580.     return true;
  581. }
  582.  
  583. void monster_start_go (edict_t *self)
  584. {
  585.     vec3_t    v;
  586.  
  587.     if (self->health <= 0)
  588.         return;
  589.  
  590.     // check for target to combat_point and change to combattarget
  591.     if (self->target)
  592.     {
  593.         qboolean    notcombat;
  594.         qboolean    fixup;
  595.         edict_t        *target;
  596.  
  597.         target = NULL;
  598.         notcombat = false;
  599.         fixup = false;
  600.         while ((target = G_Find (target, FOFS(targetname), self->target)) != NULL)
  601.         {
  602.             if (strcmp(target->classname, "point_combat") == 0)
  603.             {
  604.                 self->combattarget = self->target;
  605.                 fixup = true;
  606.             }
  607.             else
  608.             {
  609.                 notcombat = true;
  610.             }
  611.         }
  612.         if (notcombat && self->combattarget)
  613.             gi.dprintf("%s at %s has target with mixed types\n", self->classname, vtos(self->s.origin));
  614.         if (fixup)
  615.             self->target = NULL;
  616.     }
  617.  
  618.     // validate combattarget
  619.     if (self->combattarget)
  620.     {
  621.         edict_t        *target;
  622.  
  623.         target = NULL;
  624.         while ((target = G_Find (target, FOFS(targetname), self->combattarget)) != NULL)
  625.         {
  626.             if (strcmp(target->classname, "point_combat") != 0)
  627.             {
  628.                 gi.dprintf("%s at (%i %i %i) has a bad combattarget %s : %s at (%i %i %i)\n",
  629.                     self->classname, (int)self->s.origin[0], (int)self->s.origin[1], (int)self->s.origin[2],
  630.                     self->combattarget, target->classname, (int)target->s.origin[0], (int)target->s.origin[1],
  631.                     (int)target->s.origin[2]);
  632.             }
  633.         }
  634.     }
  635.  
  636.     if (self->target)
  637.     {
  638.         self->goalentity = self->movetarget = G_PickTarget(self->target);
  639.         if (!self->movetarget)
  640.         {
  641.             gi.dprintf ("%s can't find target %s at %s\n", self->classname, self->target, vtos(self->s.origin));
  642.             self->target = NULL;
  643.             self->monsterinfo.pausetime = 100000000;
  644.             self->monsterinfo.stand (self);
  645.         }
  646.         else if (strcmp (self->movetarget->classname, "path_corner") == 0)
  647.         {
  648.             VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
  649.             self->ideal_yaw = self->s.angles[YAW] = vectoyaw(v);
  650.             self->monsterinfo.walk (self);
  651.             self->target = NULL;
  652.         }
  653.         else
  654.         {
  655.             self->goalentity = self->movetarget = NULL;
  656.             self->monsterinfo.pausetime = 100000000;
  657.             self->monsterinfo.stand (self);
  658.         }
  659.     }
  660.     else
  661.     {
  662.         self->monsterinfo.pausetime = 100000000;
  663.         self->monsterinfo.stand (self);
  664.     }
  665.  
  666.     self->think = monster_think;
  667.     self->nextthink = level.time + FRAMETIME;
  668. }
  669.  
  670.  
  671. void walkmonster_start_go (edict_t *self)
  672. {
  673.     if (!(self->spawnflags & 2) && level.time < 1)
  674.     {
  675.         M_droptofloor (self);
  676.  
  677.         if (self->groundentity)
  678.             if (!M_walkmove (self, 0, 0))
  679.                 gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
  680.     }
  681.     
  682.     if (!self->yaw_speed)
  683.         self->yaw_speed = 20;
  684.     self->viewheight = 25;
  685.  
  686.     monster_start_go (self);
  687.  
  688.     if (self->spawnflags & 2)
  689.         monster_triggered_start (self);
  690. }
  691.  
  692. void walkmonster_start (edict_t *self)
  693. {
  694.     self->think = walkmonster_start_go;
  695.     monster_start (self);
  696. }
  697.  
  698.  
  699. void flymonster_start_go (edict_t *self)
  700. {
  701.     if (!M_walkmove (self, 0, 0))
  702.         gi.dprintf ("%s in solid at %s\n", self->classname, vtos(self->s.origin));
  703.  
  704.     if (!self->yaw_speed)
  705.         self->yaw_speed = 10;
  706.     self->viewheight = 25;
  707.  
  708.     monster_start_go (self);
  709.  
  710.     if (self->spawnflags & 2)
  711.         monster_triggered_start (self);
  712. }
  713.  
  714.  
  715. void flymonster_start (edict_t *self)
  716. {
  717.     self->flags |= FL_FLY;
  718.     self->think = flymonster_start_go;
  719.     monster_start (self);
  720. }
  721.  
  722.  
  723. void swimmonster_start_go (edict_t *self)
  724. {
  725.     if (!self->yaw_speed)
  726.         self->yaw_speed = 10;
  727.     self->viewheight = 10;
  728.  
  729.     monster_start_go (self);
  730.  
  731.     if (self->spawnflags & 2)
  732.         monster_triggered_start (self);
  733. }
  734.  
  735. void swimmonster_start (edict_t *self)
  736. {
  737.     self->flags |= FL_SWIM;
  738.     self->think = swimmonster_start_go;
  739.     monster_start (self);
  740. }
  741.